from typing import Optional
from sqlmodel import select, func, col

# from sqlmodel.ext.asyncio.session import AsyncSession
from . import models
from .db import Session, engine
from .utils import encrypt_password, verify_password


# 定义业务逻辑异常类型
class LogicalException(Exception): ...


# 用户相关服务
def register_user(user: models.UserCreate):
    with Session(engine) as session:
        # 检查邮箱是否已注册
        stmt = select(models.User).where(models.User.email == user.email)
        if session.exec(stmt).first():
            raise LogicalException("Email already registered")

        # 检查昵称是否已被使用
        stmt = select(models.User).where(models.User.nickname == user.nickname)
        select(models.User).filter_by(nickname=user.nickname)
        if session.exec(stmt).first():
            raise LogicalException("Nickname already taken")

        hashed_password = encrypt_password(user.password)
        db_user = models.User(
            email=user.email,
            nickname=user.nickname,
            password=hashed_password,
            avatar=user.avatar,
        )
        session.add(db_user)
        session.commit()
        session.refresh(db_user)
        return db_user


def authenticate_user(email: str, password: str):
    with Session(engine) as session:
        stmt = select(models.User).where(models.User.email == email)
        user = session.exec(stmt).first()
        if not user or not verify_password(password, user.password):
            raise LogicalException("Incorrect email or password")
        return user


def get_user_profile(user_id: int):
    with Session(engine) as session:
        stmt = select(models.User).where(models.User.id == user_id)
        user = session.exec(stmt).first()
        if not user:
            raise LogicalException("User not found")
        return user


# 标签相关服务
def create_tag(tag: models.TagCreate, user_id: int):
    with Session(engine) as session:
        stmt = select(models.Tag).where(models.Tag.name == tag.name)
        if session.exec(stmt).first():
            raise LogicalException("Tag already exists")

        db_tag = models.Tag(name=tag.name, owner_id=user_id)
        session.add(db_tag)
        session.commit()
        session.refresh(db_tag)
        return db_tag


def get_user_tags(user_id: int, skip: int = 0, limit: int = 100):
    with Session(engine) as session:
        stmt = (
            select(models.Tag)
            .where(models.Tag.owner_id == user_id)
            .offset(skip)
            .limit(limit)
        )
        return session.exec(stmt).all()


# 提示词相关服务
def create_prompt(prompt: models.PromptCreate, user_id: int):
    with Session(engine) as session:
        # 验证所有标签是否存在
        stmt = select(models.Tag).where(col(models.Tag.id).in_(prompt.tags))
        existing_tags = session.exec(stmt).all()
        existing_tag_ids = {tag.id for tag in existing_tags}

        # 检查是否有不存在的标签
        missing_tag_ids = set(prompt.tags) - existing_tag_ids
        if missing_tag_ids:
            raise LogicalException(f"Tag {missing_tag_ids.pop()} not found")

        db_prompt = models.Prompt(
            title=prompt.title,
            content=prompt.content,
            is_published=prompt.is_published,
            owner_id=user_id,
        )
        session.add(db_prompt)
        session.commit()

        # 添加标签关联
        for tag_id in prompt.tags:
            tag = session.get(models.Tag, tag_id)
            if tag:
                db_prompt.tags.append(tag)

        session.commit()
        session.refresh(db_prompt)
        return db_prompt


def get_prompts(
    skip: int = 0,
    limit: int = 100,
    keyword: Optional[str] = None,
    user_id: Optional[int] = None,
):
    with Session(engine) as session:
        query = select(models.Prompt)

        if keyword:
            query = query.where(
                (func.lower(models.Prompt.title).contains(func.lower(keyword)))
                | (func.lower(models.Prompt.content).contains(func.lower(keyword)))
            )
        if user_id:
            query = query.where(models.Prompt.owner_id == user_id)
        else:
            query = query.where(models.Prompt.is_published == True)

        query = query.offset(skip).limit(limit)
        return session.exec(query).all()


def get_prompt(prompt_id: int):
    with Session(engine) as session:
        stmt = select(models.Prompt).where(models.Prompt.id == prompt_id)
        prompt = session.exec(stmt).first()
        if not prompt:
            raise LogicalException("Prompt not found")
        return prompt


def like_prompt(prompt_id: int):
    with Session(engine) as session:
        prompt = session.get(models.Prompt, prompt_id)
        if not prompt:
            raise LogicalException("Prompt not found")
        prompt.likes += 1
        session.commit()
        session.refresh(prompt)
        return prompt


# 收藏相关服务
def create_collection(user_id: int, prompt_id: int):
    with Session(engine) as session:
        # 验证提示词是否存在
        prompt = session.get(models.Prompt, prompt_id)
        if not prompt:
            raise LogicalException("Prompt not found")

        # 验证是否已经收藏
        stmt = select(models.Collection).where(
            models.Collection.user_id == user_id,
            models.Collection.prompt_id == prompt_id,
        )
        if session.exec(stmt).first():
            raise LogicalException("Already collected")

        collection = models.Collection(user_id=user_id, prompt_id=prompt_id)
        session.add(collection)
        session.commit()
        session.refresh(collection)
        return collection


def get_user_collections(user_id: int, skip: int = 0, limit: int = 100):
    with Session(engine) as session:
        stmt = (
            select(models.Collection)
            .where(models.Collection.user_id == user_id)
            .offset(skip)
            .limit(limit)
        )
        return session.exec(stmt).all()


def delete_collection(user_id: int, prompt_id: int):
    with Session(engine) as session:
        stmt = select(models.Collection).where(
            models.Collection.user_id == user_id,
            models.Collection.prompt_id == prompt_id,
        )
        collection = session.exec(stmt).first()
        if not collection:
            raise LogicalException("Collection not found")

        session.delete(collection)
        session.commit()
        return {"success": True}
